#include "chatdialog.h"
#include "ui_chatdialog.h"
#include <QByteArray>
#include <QDataStream>

// 定义包头结构（与服务器一致）
struct MessageHeader {
    quint32 msg_len;  // 消息长度
};

ChatDialog::ChatDialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::ChatDialog)
    , m_sock(nullptr)
    , localIP("")
{
    ui->setupUi(this);

     localIP = getLocalIPAddress();

    ui->btnSend->setDisabled(true);

    m_sock = new QTcpSocket(this);

    connect(m_sock, &QTcpSocket::connected, this, &ChatDialog::connectSuccess);
    connect(m_sock, &QTcpSocket::readyRead, this, &ChatDialog::recvMsg);
    connect(m_sock, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), this, &ChatDialog::errorHandle);

    ui->edtRecord->appendPlainText("[系统] 正在连接服务器，请稍候...\n\n");
   // m_sock->connectToHost("localhost IP", 8888);
    m_sock->connectToHost("10.11.1.86", 8888);
}

ChatDialog::~ChatDialog()
{
    delete ui;
}

//发送数据包（处理粘包）
void ChatDialog::sendPacket(const QByteArray &data)
{
    if (!m_sock || m_sock->state() != QAbstractSocket::ConnectedState) {
        return;
    }
    
    // 构造包头
    MessageHeader header;
    header.msg_len = data.size();  // 消息体长度
    
    // 将整个数据包写入字节数组
    QByteArray packet;
    QDataStream stream(&packet, QIODevice::WriteOnly);
    stream.setByteOrder(QDataStream::BigEndian);  // 网络字节序
    
    // 先写入包头
    stream << header.msg_len;
    // 再写入消息体
    stream.writeRawData(data.constData(), data.size());
    
    // 发送完整数据包
    m_sock->write(packet);
}

//接收数据包（处理粘包）
void ChatDialog::recvMsg()
{
    static QByteArray buffer;
    buffer.append(m_sock->readAll());

    while (buffer.size() >= 4) {  // 至少要有包头
        // 解析包头（大端序）
        quint32 msg_len = ((quint8)buffer[0] << 24) |
                         ((quint8)buffer[1] << 16) |
                         ((quint8)buffer[2] << 8) |
                         (quint8)buffer[3];

        //修复警告：将 buffer.size() 转换为 quint32 进行比较
        if (static_cast<quint32>(buffer.size()) >= 4 + msg_len) {
            // 提取消息体
            QByteArray messageData = buffer.mid(4, msg_len);
            QString message = QString::fromUtf8(messageData);
            ui->edtRecord->appendPlainText(message + "\n\n");

            // 从缓冲区移除已处理的数据
            buffer = buffer.mid(4 + msg_len);
        } else {
            // 数据不完整，等待更多数据
            break;
        }
    }
}


void ChatDialog::connectSuccess()
{
    ui->edtRecord->appendPlainText("[系统] 连接服务器成功！\n\n");
    ui->btnSend->setEnabled(true);
}

void ChatDialog::errorHandle(QAbstractSocket::SocketError socketError)
{
    ui->edtRecord->appendPlainText("[系统] 连接服务器失败！\n\n");
    ui->btnSend->setEnabled(false);
}


QString ChatDialog::getLocalIPAddress()
{
    QString localIP;
    
    // 获取所有网络接口
    QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
    
    foreach (const QNetworkInterface &interface, interfaces) {
        // 只获取激活的且不是回环的接口
        if (interface.flags().testFlag(QNetworkInterface::IsUp) &&
            interface.flags().testFlag(QNetworkInterface::IsRunning) &&
            !interface.flags().testFlag(QNetworkInterface::IsLoopBack)) {
            
            // 获取该接口的所有IP地址
            QList<QNetworkAddressEntry> entries = interface.addressEntries();
            foreach (const QNetworkAddressEntry &entry, entries) {
                // 只获取IPv4地址
                if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
                    localIP = entry.ip().toString();
                    // 优先选择非内部地址
                    if (!localIP.startsWith("192.168") && !localIP.startsWith("127.") && !localIP.startsWith("172.")) {
                        return localIP;
                    }
                }
            }
        }
    }
    
    // 如果没有找到合适的IP，返回本地回环地址
    return localIP.isEmpty() ? "127.0.0.1" : localIP;
}

void ChatDialog::on_btnSend_clicked()
{
    QString msg = ui->edtMsg->toPlainText();

     if (msg.isEmpty()) {
        return;
    }

    // 使用封包函数发送数据
    QByteArray messageData = msg.toUtf8();
    sendPacket(messageData);
    
    // 清空输入框
    ui->edtMsg->clear();
    
    // 在聊天记录中显示自己发送的消息
    ui->edtRecord->appendPlainText("[" + localIP + "]" + "发送: "+ msg + "\n\n");
}
